04 设计模式——工厂方法模式

返回设计模式博客目录

介绍


工厂方法模式:定义一个用于创建对象的接口,让子类决定实例化哪个类

工厂方法模式(FACTORY METHOD)是一种常用的类创建型设计模式,此模式的核心精神是封装类中变化的部分,提取其中个性化善变的部分为独立类,通过依赖注入以达到解耦、复用和方便后期维护拓展的目的。在任何需要生成复杂对象的地方,都可以使用工厂方法模式。复杂对象适合使用工厂模式,用 new 就可以完成创建的对象无需使用工厂模式。

它的核心结构有四个角色,分别是抽象工厂、具体工厂、抽象产品、具体产品。

通用模式代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
// 抽象产品类
public abstract class Product {
/**
* 产品类的抽象方法,由具体的产品类去实现
*/
public abstract void method();
}
// 具体产品类 A
public class ConcreteProductA extends Product {
@Override
public void method() {
System.out.println("产品 A");
}
}
// 具体产品类 B
public class ConcreteProductB extends Product {
@Override
public void method() {
System.out.println("产品 B");
}
}
// 抽象工厂类
public abstract class Factory {
/**
* 抽象工厂方法,具体由子类去实现
* @return 具体的产品类型
*/
public abstract Product createProduct();
}
// 具体工厂类
public class ConcreteFactory extends Factory {
@Override
public Product createProduct() {
return new ConcreteProductA();
}
}

调用

1
2
3
Factory factory = new ConcreteFactory();
Product p = factory.createProduct();
p.method();

这里我们得到的产品对象时 ConcreteProductA 的实例,如果想得到 ConcreteProductB 的实例,更改 ConcreteFactory 中的逻辑即可;或者是新建一个 Factory 的具体实现子类,专门生产 ConcreteProductB 的实例。当然,我们也可以利用反射的方式来简化操作。具体如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
public abstract class Factory {
/**
* @param clz 产品对象类型
* @return 具体的产品类型
*/
public abstract <T extends Product> T createProduct(Class<T> clz);
}
public class ConcreteFactory extends Factory {
@Override
public <T extends Product> T createProduct(Class<T> clz) {
Product p = null;
try {
p = (Product) Class.forName(clz.getName()).newInstance();
} catch (Exception e) {
e.printStackTrace();
}
return (T) p;
}
}

调用:

1
2
3
4
5
Factory factory = new ConcreteFactory();
Product productA = factory.createProduct(ConcreteProductA.class);
Product productB = factory.createProduct(ConcreteProductB.class);
productA.method();
productB.method();

当我们的工厂只有一个的时候,可以简化掉抽象工厂类,并提供一个静态方法即可。

1
2
3
4
5
public class Factory {
public static Product createProduct() {
return new ConcreteProductA();
}
}

工厂方法模式是完全符合设计原则的,其降低了对象之间的耦合度。而且,工厂方法模式依赖于抽象的架构,其将实例化的任务交由子类去完成,有非常好的扩展性。

ANDROID 源码中的工厂方法模式


大家平时开发中经常会使用到的数据结构中其实也隐藏着对工厂方法模式的应用,以 List 和 Set 为例,List 和 Set 继承自 Collection 接口,而 Collection 接口继承于 Iterable 接口,Iterable 接口很简单,就一个 iterator 方法。

1
2
3
public interface Iterable<T> {
Iterator<T> iterator();
}

这意味着 List 和 Set 接口也会继承该方法,平时比较常用的两个间接实现类 ArrayList 和 HashSet 中的 iterator 方法的实现就是构造并返回一个迭代器对象。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
public class ArrayList<E> extends AbstractList<E> implements Cloneable,
Serializable, RandomAccess {
@Override
public Iterator<E> iterator() {
return new ArrayListIterator();
}
private class ArrayListIterator implements Iterator<E> {
/** Number of elements remaining in this iteration */
private int remaining = size;
/** Index of element that remove() would remove, or -1 if no such elt */
private int removalIndex = -1;
/** The expected modCount value */
private int expectedModCount = modCount;
public boolean hasNext() {
return remaining != 0;
}
@SuppressWarnings("unchecked") public E next() {
ArrayList<E> ourList = ArrayList.this;
int rem = remaining;
if (ourList.modCount != expectedModCount) {
throw new ConcurrentModificationException();
}
if (rem == 0) {
throw new NoSuchElementException();
}
remaining = rem - 1;
return (E) ourList.array[removalIndex = ourList.size - rem];
}
public void remove() {
Object[] a = array;
int removalIdx = removalIndex;
if (modCount != expectedModCount) {
throw new ConcurrentModificationException();
}
if (removalIdx < 0) {
throw new IllegalStateException();
}
System.arraycopy(a, removalIdx + 1, a, removalIdx, remaining);
a[--size] = null; // Prevent memory leak
removalIndex = -1;
expectedModCount = ++modCount;
}
}
}

ArrayList 中的 iterator 方法其实就相当于一个工厂方法,专为 new 对象而生,这里的 iterator 方法是构造并返回一个具体的迭代器。再看看下面的对应关系:

1
2
Iterator ————> Product; ArrayListIteratorr ————> ConcreteProduct。
Iterable/List ————> Factory; ArrayList ————> ConcreteFactory。

当然,Java 源码中对工厂方法的应用范例也不少,大家可以自己查看 Set 的源码。ANDROID 中对工厂方法模式的应用更多,读者其实第一次接触 ANDROID 时就已经遇到了但未察觉到,相信以下代码对一个 ANDROID 新手来说都不陌生。

1
2
3
4
5
6
7
public class TestActivity extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(new LinearLayout(this));
}
}

这里构造一个线性布局 LinearLayout 对象并设置为当前 Activity 的根布局,这段代码看似再平常不过了,实质上,onCreate 方法就相当于一个工厂方法,为什么呢?因为我们知道 LinearLayout 是一个 ViewGroup,而 ViewGroup 又继承于 View,简单地说就是,所有控件都是 View 的子类,上面的代码中,我们在 TestActivity 的 onCreate 方法中构造一个 View 对象,并设置为当前界面的 ContentView 返回给 framework 处理,如果现在又有一个 LoginActivity,这时我们又在其 onCreate 方法中通过 setContentView 方法设置另外不同的 View,这是不是就是一个工厂模式的结构呢?其实设计模式离我们非常近。

示例:数据持久化


ANDROID 中数据持久化为我们提供了 SharePreference、 SQLite 和普通的文件存储等方式。但是对数据的操作都是增删改查,可以把这些共同的操作抽象出来作为抽象产品类,然后每一种持久化方法作为具体产品。

抽象产品中定义操作的方法,即增删改查。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
public abstract class AbstractIoHandler {
/**
* 添加个人信息
*
* @param id 身份证号码
* @param name 姓名
*/
public abstract void add(String id, String name);
/**
* 根据ID删除一条信息
*
* @param id 身份证
*/
public abstract void remove(String id);
/**
* 更新个人信息
*
* @param id 身份证
* @param name 姓名
*/
public abstract void update(String id, String name);
/**
* 查询ID对应的信息
*
* @param id 身份证
* @return 人名
*/
public abstract String query(String id);
}

具体的产品,持久化的类型,比如利用文件来持久化。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
public class FileHandler extends AbstractIoHandler {
@Override
public void add(String id, String name){
// 业务处理
}
@Override
public void remove(String id) {
// 业务处理
}
@Override
public void update(String id, String name) {
// 业务处理
}
@Override
public String query(String id) {
return "";
}
}

然后是我们的工厂方法,这里仍然采用反射的方式。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
public class IoFactory {
/**
* 获取IoHandler
*
* @param clz AbstractIoHandler类型的类
* @return AbstractIoHandler对象
*/
public static <T extends AbstractIoHandler> T getIoHandler(Class<T> clz) {
AbstractIoHandler handler = null;
try {
handler = (AbstractIoHandler) Class.forName(clz.getName()).newInstance();
} catch (Exception e) {
e.printStackTrace();
}
return (T) handler;
}
}

在需要进行数据持久化的地方调用工厂方法:

1
2
AbstractIoHandler ioHandler = IoFactory.getIoHandler(FileHandler.class);
System.out.println(ioHandler.query("123456"));

这里的例子简化了很多,还有数据库 SQLite 以及 SharePreference 的持久化的类就没有写了。